package com.fetaphon.blelibrary;

import android.bluetooth.BluetoothGatt;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.widget.Toast;

import com.fetaphon.blelibrary.callback.BleGattCallback;
import com.fetaphon.blelibrary.callback.BleNotifyCallback;
import com.fetaphon.blelibrary.callback.BleScanCallback;
import com.fetaphon.blelibrary.callback.BleStatusCallback;
import com.fetaphon.blelibrary.callback.BleWriteCallback;
import com.fetaphon.blelibrary.callback.DataCallback;
import com.fetaphon.blelibrary.callback.ScanCallBack;
import com.fetaphon.blelibrary.entity.BleDevice;
import com.fetaphon.blelibrary.entity.BleStatus;
import com.fetaphon.blelibrary.entity.data.BmsData;
import com.fetaphon.blelibrary.entity.data.BmsHvParams;
import com.fetaphon.blelibrary.entity.data.CurrentParams;
import com.fetaphon.blelibrary.entity.data.DxParams;
import com.fetaphon.blelibrary.entity.data.MosStatus;
import com.fetaphon.blelibrary.entity.data.Packet;
import com.fetaphon.blelibrary.entity.data.TempParams;
import com.fetaphon.blelibrary.entity.data.VoltageParams;
import com.fetaphon.blelibrary.exception.BleException;
import com.fetaphon.blelibrary.utils.BleLog;
import com.fetaphon.blelibrary.utils.ByteUtils;
import com.fetaphon.blelibrary.utils.GsonUtils;
import com.fetaphon.blelibrary.utils.JniUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import androidx.annotation.StringDef;

import static com.fetaphon.blelibrary.utils.ByteUtils.toHexString;

public class BMS {

    private static final String UUID_SERVICE_NOTIFY = "0000fff0-0000-1000-8000-00805f9b34fb";
    private static final String UUID_NOTIFY = "0000fff1-0000-1000-8000-00805f9b34fb";
    private static final String UUID_SERVICE_WRITE = "0000ffd0-0000-1000-8000-00805f9b34fb";
    private static final String UUID_WRITE = "0000ffd1-0000-1000-8000-00805f9b34fb";

    private static final int MSG_OPEN_NOTIFY = 0x01;
    private static final int MSG_OPEN_NOTIFY_SUCCESS = 0x02;
    private static final int MSG_OPEN_NOTIFY_FAIL = 0x03;
    private static final int MSG_REC_DATA = 0x04;

    //帧类型
    private static final String FRAME_TYPE_CONTROL = "000";
    private static final String FRAME_TYPE_QUERY = "001";
    private static final String FRAME_TYPE_SET = "010";
    private static final String FRAME_TYPE_DATA = "011";
    private static final String FRAME_TYPE_CONFIRM = "100";

    @StringDef({FRAME_TYPE_CONTROL, FRAME_TYPE_QUERY, FRAME_TYPE_SET, FRAME_TYPE_DATA,
            FRAME_TYPE_CONFIRM})
    private @interface FrameType {
    }

    //ACK
    private static final String ACK_TRUE = "1";
    private static final String ACK_FALSE = "0";

    @StringDef({ACK_TRUE, ACK_FALSE})
    private @interface ACKType {
    }

    private Context mContext;
    private BleDevice mBleDevice;
    private boolean isStop;
    private AtomicInteger mSeq = new AtomicInteger(0);
    private BleStatusCallback mBleStatusCallback;
    private DataCallback mDataCallback;

    private List<String> srcData = new ArrayList<>();

    public List<String> getSrcData() {
        return srcData;
    }

    /**
     * 蓝牙状态以及数据回调
     *
     * @param bleStatusCallback 蓝牙连接状态
     * @param dataCallback      数据
     */
    public void setBMSCallback(BleStatusCallback bleStatusCallback, DataCallback dataCallback) {
        mBleStatusCallback = bleStatusCallback;
        mDataCallback = dataCallback;
    }

    public static BMS getInstance() {
        return BMSManagerHolder.mInstance;
    }

    private static class BMSManagerHolder {
        public static BMS mInstance = new BMS();
    }

    private BMS() {

    }

    public void init(Context context) {
        mContext = context.getApplicationContext();
        BleManager.options()
                .enableLog(true)                          //开启log
                .setScanDeviceMac("")                     //扫描指定macAddress
//                .setScanDeviceNames()           //扫描指定的设备名（多）
                .setScanFuzzy(true)                       //是否模糊扫描设备名
                .setScanTimeOut(5 * 1000)                 //扫描超时时间
                .setScanAutoConnect(false)                //扫描后是否自动连接
//                .setServiceUUIDs()            //设置UUID（多）
                .setAutoConnect(false)                    //是否自动连接
                .setMaxConnectCount(3)                    //最大连接数
                .setReConnectCount(3, 3000)//失败重连次数、间隔
                .setConnectTimeOut(10 * 1000)             //连接超时时间
                .setOperateTimeout(3 * 1000)              //操作间隔
                .setSplitWriteNum(20)                     //设置写分包大小
                .create(context);
    }

    private Handler mHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_OPEN_NOTIFY://打开通知
                    mBleDevice = (BleDevice) msg.obj;
                    openNotify(mBleDevice);
                    break;
                case MSG_OPEN_NOTIFY_SUCCESS://打开通知成功
                    mBleDevice = (BleDevice) msg.obj;
                    if (mBleStatusCallback != null) {
                        mBleStatusCallback.bleStatus(mBleDevice, BleStatus.CONNECT_SUCCESS);
                    }
                    break;
                case MSG_OPEN_NOTIFY_FAIL://打开通知失败
                    mBleDevice = (BleDevice) msg.obj;
                    disconnect();
                    if (mBleStatusCallback != null) {
                        mBleStatusCallback.bleStatus(mBleDevice, BleStatus.CONNECT_FAIL);
                    }
                    break;
                case MSG_REC_DATA://接收的数据
                    Packet packet = (Packet) msg.obj;
                    String frameType = packet.getFrame_type();
                    int cmd = packet.getCmd();
                    if (packet.getData().length == 0) return;
                    byte[] data = ByteUtils.subBytes(packet.getData(), 2, packet.getData().length - 2);
                    //这边只回调出FRAME_TYPE_DATA
                    if (!frameType.equals(FRAME_TYPE_DATA)) return;

                    if (cmd == 0x01) {//BMS实时数据
                        BmsData bmsData = new BmsData(data);
                        if (bmsData != null && mDataCallback != null) {
                            mDataCallback.bmsData(bmsData);
                        }
                    } else if (cmd == 0x02) {//电芯特性
                        DxParams dxParams = new DxParams(data);
                        safeToast("电芯特性:" + dxParams.toString());
                        if (dxParams != null && mDataCallback != null) {
                            mDataCallback.dxParams(dxParams);
                        }
                    } else if (cmd == 0x03) {//BMS硬件参数
                        BmsHvParams bmsHvParams = new BmsHvParams(data);
                        if (bmsHvParams != null && mDataCallback != null) {
                            mDataCallback.bmsHvParams(bmsHvParams);
                        }
                    } else if (cmd == 0x04) {//MOS状态
                        MosStatus mosStatus = new MosStatus(data);
                        if (mosStatus != null && mDataCallback != null) {
                            mDataCallback.mosStatus(mosStatus);
                        }
                    } else if (cmd == 0x05) {//电压保护参数
                        VoltageParams voltageParams = new VoltageParams(data);
                        if (voltageParams != null && mDataCallback != null) {
                            mDataCallback.voltageParams(voltageParams);
                        }
                    } else if (cmd == 0x06) {//电流保护参数
                        CurrentParams currentParams = new CurrentParams(data);
                        if (currentParams != null && mDataCallback != null) {
                            mDataCallback.currentParams(currentParams);
                        }
                    } else if (cmd == 0x07) {//温度保护参数
                        TempParams tempParams = new TempParams(data);
                        if (tempParams != null && mDataCallback != null) {
                            mDataCallback.tempParams(tempParams);
                        }
                    }
                    break;
            }
        }


    };

    //-----------------------------------------1、蓝牙操作相关-------------------------------------------------

    /**
     * 扫描
     *
     * @param scanCallBack
     */
    public void scan(final ScanCallBack scanCallBack) {
        BleManager.getInstance().scan(new BleScanCallback() {
            @Override
            public void onScanFinished(List<BleDevice> scanResultList) {
                if (scanCallBack != null) {
                    scanCallBack.onScanComplete(scanResultList);
                }
            }

            @Override
            public void onScanStarted(boolean success) {
                if (scanCallBack != null) {
                    scanCallBack.onScanStart(success);
                }
            }

            @Override
            public void onScanning(BleDevice bleDevice) {
            }
        });
    }

    /**
     * 连接
     *
     * @param bleDevice
     */
    public void connect(final BleDevice bleDevice) {
        mBleDevice = bleDevice;
        BleManager.getInstance().connect(bleDevice, new BleGattCallback() {
            @Override
            public void onStartConnect() {
                if (mBleStatusCallback != null) {
                    mBleStatusCallback.bleStatus(bleDevice, BleStatus.CONNECT_START);
                }
            }

            @Override
            public void onConnectFail(BleDevice bleDevice, BleException exception) {
                if (mBleStatusCallback != null) {
                    mBleStatusCallback.bleStatus(bleDevice, BleStatus.CONNECT_FAIL);
                }
            }

            @Override
            public void onConnectSuccess(BleDevice bleDevice, BluetoothGatt gatt, int status) {
                Message message = mHandler.obtainMessage(MSG_OPEN_NOTIFY);
                message.obj = bleDevice;
                mHandler.sendMessageDelayed(message, 500);
            }

            @Override
            public void onDisConnected(boolean isActiveDisConnected, BleDevice device, BluetoothGatt gatt,
                                       int status) {
                if (mBleStatusCallback != null) {
                    mBleStatusCallback.bleStatus(bleDevice, isActiveDisConnected ?
                            BleStatus.DISCONNECTED_ACTIVE :
                            BleStatus.DISCONNECTED);
                }
            }
        });
    }

    /**
     * 打开通知
     *
     * @param bleDevice
     */
    private void openNotify(final BleDevice bleDevice) {
        mBleDevice = bleDevice;
        BleManager.getInstance().notify(bleDevice, UUID_SERVICE_NOTIFY, UUID_NOTIFY, false,
                new BleNotifyCallback() {
                    @Override
                    public void onNotifySuccess() {
                        BleLog.i("notify Success");
                        Message message = mHandler.obtainMessage(MSG_OPEN_NOTIFY_SUCCESS);
                        message.obj = bleDevice;
                        mHandler.sendMessage(message);
                    }

                    @Override
                    public void onNotifyFailure(BleException exception) {
                        BleLog.i("notify failure:" + exception.getDescription());
                        Message message = mHandler.obtainMessage(MSG_OPEN_NOTIFY_FAIL);
                        message.obj = bleDevice;
                        mHandler.sendMessage(message);
                    }

                    @Override
                    public void onCharacteristicChanged(byte[] data) {
                        parse(data);
                    }
                });
    }

    /**
     * 写入数据
     *
     * @param bytes
     */
    private void write(byte[] bytes, final BleWriteCallback writeCallback) {
        BleManager.getInstance().write(mBleDevice, UUID_SERVICE_WRITE, UUID_WRITE, bytes,
                new BleWriteCallback() {
                    @Override
                    public void onWriteSuccess(int current, int total, byte[] justWrite) {
                        BleLog.i("写入成功");
                        if (writeCallback != null) {
                            writeCallback.onWriteSuccess(current, total, justWrite);
                        }
                    }

                    @Override
                    public void onWriteFailure(BleException exception) {
                        BleLog.i("写入失败");
                        if (writeCallback != null) {
                            writeCallback.onWriteFailure(exception);
                        }
                    }
                });
    }

    /**
     * 断开连接
     */
    public void disconnect() {
        BleManager.getInstance().disconnect(mBleDevice);
    }

    //----------------------------------------2、发送的指令集---------------------------------------------

    /**************控制***************/
    /**
     * (a)激活BMS
     *
     * @param type 0-去激活 1-激活
     */
    public void sendActivateBMS(int type, BleWriteCallback writeCallback) {
        byte[] cmd = ByteUtils.int2Bytes(0x00, 1);
        byte[] len = ByteUtils.int2Bytes(1, 2);
        byte[] data = ByteUtils.int2Bytes(type, 1);
        byte[] datas = ByteUtils.byteMerge(cmd, len, data);

        byte[] packet = createPacket(FRAME_TYPE_CONTROL, datas);
        BleLog.d("发送指令-激活/去激活BMS：" + ByteUtils.toHexString(packet));
        write(packet, writeCallback);
    }

    /**
     * (b)打开/关闭充电MOS
     *
     * @param isOn true-打开 false-关闭
     */
    public void sendBatteryMOS(boolean isOn, BleWriteCallback writeCallback) {
        byte[] cmd = ByteUtils.int2Bytes(0x01, 1);
        byte[] len = ByteUtils.int2Bytes(1, 2);
        byte[] data = ByteUtils.int2Bytes(isOn ? 1 : 0, 1);
        byte[] datas = ByteUtils.byteMerge(cmd, len, data);

        byte[] packet = createPacket(FRAME_TYPE_CONTROL, datas);
        BleLog.d("发送指令-打开/关闭充电MOS：" + ByteUtils.toHexString(packet));
        write(packet, writeCallback);
    }

    /**
     * (c)打开/关闭放电MOS
     *
     * @param isOn true-打开 false-关闭
     */
    public void sendBatteryDischargeMOS(boolean isOn, BleWriteCallback writeCallback) {
        byte[] cmd = ByteUtils.int2Bytes(0x02, 1);
        byte[] len = ByteUtils.int2Bytes(1, 2);
        byte[] data = ByteUtils.int2Bytes(isOn ? 1 : 0, 1);
        byte[] datas = ByteUtils.byteMerge(cmd, len, data);

        byte[] packet = createPacket(FRAME_TYPE_CONTROL, datas);
        BleLog.d("发送指令-打开/关闭放电MOS：" + ByteUtils.toHexString(packet));
        write(packet, writeCallback);
    }

    /**
     * (d)重启BMS
     */
    public void sendReStartBMS(BleWriteCallback writeCallback) {
        byte[] cmd = ByteUtils.int2Bytes(0x03, 1);
        byte[] len = ByteUtils.int2Bytes(0, 2);
        byte[] datas = ByteUtils.byteMerge(cmd, len);

        byte[] packet = createPacket(FRAME_TYPE_CONTROL, datas);
        BleLog.d("发送指令-重启BMS：" + ByteUtils.toHexString(packet));
        write(packet, writeCallback);
    }

    /**
     * (e)BMS关闭系统
     */
    public void sendCloseBMS(BleWriteCallback writeCallback) {
        byte[] cmd = ByteUtils.int2Bytes(0x04, 1);
        byte[] len = ByteUtils.int2Bytes(0, 2);
        byte[] datas = ByteUtils.byteMerge(cmd, len);

        byte[] packet = createPacket(FRAME_TYPE_CONTROL, datas);
        BleLog.d("发送指令-BMS关闭系统：" + ByteUtils.toHexString(packet));
        write(packet, writeCallback);
    }

    /**************查询***************/

    /**
     * 查询BMS实时数据
     * 0x01
     *
     * @param writeCallback
     */
    public void sendQueryBMS(BleWriteCallback writeCallback) {
        byte[] cmd = ByteUtils.int2Bytes(0x01, 1);
        byte[] len = ByteUtils.int2Bytes(0, 2);
        byte[] datas = ByteUtils.byteMerge(cmd, len);

        byte[] packet = createPacket(FRAME_TYPE_QUERY, datas);
        BleLog.d("发送指令-查询BMS实时数据：" + ByteUtils.toHexString(packet));
        write(packet, writeCallback);
    }

    /**
     * 查询电芯特性
     * 0x02
     *
     * @param writeCallback
     */
    public void sendQueryDX(BleWriteCallback writeCallback) {
        byte[] cmd = ByteUtils.int2Bytes(0x02, 1);
        byte[] len = ByteUtils.int2Bytes(0, 2);
        byte[] datas = ByteUtils.byteMerge(cmd, len);

        byte[] packet = createPacket(FRAME_TYPE_QUERY, datas);
        BleLog.d("发送指令-查询电芯特性：" + ByteUtils.toHexString(packet));
        write(packet, writeCallback);
    }

    /**
     * 查询BMS硬件参数
     * 0x03
     *
     * @param writeCallback
     */
    public void sendQueryBmsHvParams(BleWriteCallback writeCallback) {
        byte[] cmd = ByteUtils.int2Bytes(0x03, 1);
        byte[] len = ByteUtils.int2Bytes(0, 2);
        byte[] datas = ByteUtils.byteMerge(cmd, len);

        byte[] packet = createPacket(FRAME_TYPE_QUERY, datas);
        BleLog.d("发送指令-查询BMS硬件参数：" + ByteUtils.toHexString(packet));
        write(packet, writeCallback);
    }

    /**
     * 查询MOS状态
     * 0x04
     *
     * @param writeCallback
     */
    public void sendQueryMosStatus(BleWriteCallback writeCallback) {
        byte[] cmd = ByteUtils.int2Bytes(0x04, 1);
        byte[] len = ByteUtils.int2Bytes(0, 2);
        byte[] datas = ByteUtils.byteMerge(cmd, len);

        byte[] packet = createPacket(FRAME_TYPE_QUERY, datas);
        BleLog.d("发送指令-查询MOS状态：" + ByteUtils.toHexString(packet));
        write(packet, writeCallback);
    }

    /**
     * 查询电压保护参数
     * 0x05
     *
     * @param writeCallback
     */
    public void sendQueryUParams(BleWriteCallback writeCallback) {
        byte[] cmd = ByteUtils.int2Bytes(0x05, 1);
        byte[] len = ByteUtils.int2Bytes(0, 2);
        byte[] datas = ByteUtils.byteMerge(cmd, len);

        byte[] packet = createPacket(FRAME_TYPE_QUERY, datas);
        BleLog.d("发送指令-查询电压保护参数：" + ByteUtils.toHexString(packet));
        write(packet, writeCallback);
    }

    /**
     * 查询电流保护参数
     * 0x06
     *
     * @param writeCallback
     */
    public void sendQueryVParams(BleWriteCallback writeCallback) {
        byte[] cmd = ByteUtils.int2Bytes(0x06, 1);
        byte[] len = ByteUtils.int2Bytes(0, 2);
        byte[] datas = ByteUtils.byteMerge(cmd, len);

        byte[] packet = createPacket(FRAME_TYPE_QUERY, datas);
        BleLog.d("发送指令-查询电流保护参数：" + ByteUtils.toHexString(packet));
        write(packet, writeCallback);
    }

    /**
     * 查询温度保护参数
     * 0x07
     *
     * @param writeCallback
     */
    public void sendQueryTEMPParams(BleWriteCallback writeCallback) {
        byte[] cmd = ByteUtils.int2Bytes(0x07, 1);
        byte[] len = ByteUtils.int2Bytes(0, 2);
        byte[] datas = ByteUtils.byteMerge(cmd, len);

        byte[] packet = createPacket(FRAME_TYPE_QUERY, datas);
        BleLog.d("发送指令-查询温度保护参数：" + ByteUtils.toHexString(packet));
        write(packet, writeCallback);
    }

    /**************设置***************/
    /**
     * 设置电压保护参数
     * 0x01
     *
     * @param voltageParams
     * @param writeCallback
     */
    public void sendSetUParams(VoltageParams voltageParams, BleWriteCallback writeCallback) {
        byte[] voltageParamsBytes = voltageParams.getVoltageParamsBytes();
        byte[] cmd = ByteUtils.int2Bytes(0x01, 1);
        byte[] len = ByteUtils.int2Bytes(voltageParamsBytes.length, 2);
        byte[] datas = ByteUtils.byteMerge(cmd, len, voltageParamsBytes);

        byte[] packet = createPacket(FRAME_TYPE_SET, datas);
        BleLog.d("发送指令-设置电压保护参数：" + ByteUtils.toHexString(packet));
        write(packet, writeCallback);
    }

    /**
     * 设置电流保护参数
     * 0x02
     *
     * @param currentParams
     * @param writeCallback
     */
    public void sendSetVParams(CurrentParams currentParams, BleWriteCallback writeCallback) {
        byte[] currentParamsBytes = currentParams.getCurrentParamsBytes();
        byte[] cmd = ByteUtils.int2Bytes(0x02, 1);
        byte[] len = ByteUtils.int2Bytes(currentParamsBytes.length, 2);
        byte[] datas = ByteUtils.byteMerge(cmd, len, currentParamsBytes);

        byte[] packet = createPacket(FRAME_TYPE_SET, datas);
        BleLog.d("发送指令-设置电流保护参数：" + ByteUtils.toHexString(packet));
        write(packet, writeCallback);
    }

    /**
     * 设置温度保护参数
     * 0x03
     *
     * @param tempParams
     * @param writeCallback
     */
    public void sendSetVParams(TempParams tempParams, BleWriteCallback writeCallback) {
        byte[] tempParamsBytes = tempParams.getTempParamsBytes();
        byte[] cmd = ByteUtils.int2Bytes(0x03, 1);
        byte[] len = ByteUtils.int2Bytes(tempParamsBytes.length, 2);
        byte[] datas = ByteUtils.byteMerge(cmd, len, tempParamsBytes);

        byte[] packet = createPacket(FRAME_TYPE_SET, datas);
        BleLog.d("发送指令-设置温度保护参数：" + ByteUtils.toHexString(packet));
        write(packet, writeCallback);
    }


    //----------------------------------------3、协议解析相关---------------------------------------------

    /**
     * 解析
     *
     * @param bytes 帧数据
     */
    public void parse(byte[] bytes) {
        srcData.add(ByteUtils.toHexString(bytes));
        BleLog.d("收到设备原始数据：" + ByteUtils.toHexString(bytes));
        safeToast("src data:" + ByteUtils.toHexString(bytes));
        if (isStop) return;
        String strPacket = JniUtils.getPacket(bytes);
        if (strPacket == null || strPacket.equals("")) return;
        BleLog.d("解析后的数据：" + strPacket);
        safeToast("解析后的数据：" + strPacket);
        try {
            Packet packet = GsonUtils.fromJson(strPacket.trim(), Packet.class);
            if (packet == null) return;
            Message message = mHandler.obtainMessage(MSG_REC_DATA);
            message.obj = packet;
            mHandler.sendMessage(message);
        } catch (Exception e) {
            e.printStackTrace();
            safeToast(strPacket);
        }

    }

    private void safeToast(final String msg) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
                Looper.loop();
            }
        }).start();

    }

    public void startReceiveData() {
        isStop = false;
    }

    public void stopReceiveData() {
        isStop = true;
    }

    private byte[] createPacket(@FrameType String frameType, byte[] datas) {
        if (mSeq.get() > 255) {
            mSeq.set(0);
        }
        // 协议头  4byte
        byte[] head = {0x52, 0x50, 0x42, 0x4C};
        // 长度  2bye
        byte[] len = ByteUtils.int2Bytes(12 + datas.length, 2);
        // 协议版本  2byte
        byte[] version = ByteUtils.int2Bytes(1, 2);
        // 传输字  1bye
        byte[] trans = getTransBytes(frameType);
        // 帧序号  2byte
        byte[] seq = ByteUtils.int2Bytes(mSeq.intValue(), 2);

        byte[] bytes = ByteUtils.byteMerge(head, len, version, trans, seq, datas);

        mSeq.incrementAndGet();

        byte[] checkBytes = getCheckBytes(bytes);

        String A =
                "协议头hex:" + toHexString(head) + " 长度hex:" + toHexString(len) + " 版本hex:" + toHexString(version) +
                        " 传输字hex:" + toHexString(trans) + " 序列号hex:" + toHexString(seq) + " 数据域hex:" + toHexString(datas) + " 校验域hex:" + toHexString(checkBytes);
        BleLog.d("createPacket hex：" + A);
        return ByteUtils.byteMerge(bytes, getCheckBytes(bytes));

    }

    private byte[] getTransBytes(@FrameType String frameType) {
        String framBit = "0" + frameType + ACK_FALSE + "000";
        byte[] bytes = {ByteUtils.bitToByte(framBit)};
        BleLog.d("createPacket 传输字bit:" + framBit + " hex:" + toHexString(bytes));
        return new byte[]{ByteUtils.bitToByte(framBit)};
    }

    private byte[] getCheckBytes(byte[] bytes) {
        byte sum = 0;
        for (int i = 0; i < bytes.length; i++) {
            sum += bytes[i];
        }
        return new byte[]{sum};
    }

    /**
     * 测试数据
     *
     * @param type
     * @return
     */
    public byte[] getTest(int type) {

        byte[] cmd = ByteUtils.int2Bytes(0x00, 1);
        byte[] len = ByteUtils.int2Bytes(1, 2);
        byte[] data = ByteUtils.int2Bytes(type, 1);
        byte[] datas = ByteUtils.byteMerge(cmd, len, data);

        byte[] packet = createPacket(FRAME_TYPE_CONTROL, datas);
        BleLog.d("发送指令-激活/去激活BMS：" + ByteUtils.toHexString(packet));
        return packet;
    }

}
